PadziļinÄts ieskats React komponentu arhitektÅ«rÄ, salÄ«dzinot kompozÄ«ciju un mantoÅ”anu. Uzziniet, kÄpÄc React dod priekÅ”roku kompozÄ«cijai, un apgÅ«stiet tÄdus modeļus kÄ HOC, Render Props un Hooks, lai veidotu mÄrogojamus, atkÄrtoti lietojamus komponentus.
React Komponentu ArhitektÅ«ra: KÄpÄc KompozÄ«cija PÄrspÄj MantoÅ”anu
ProgrammatÅ«ras izstrÄdes pasaulÄ arhitektÅ«rai ir milzÄ«ga nozÄ«me. Veids, kÄ mÄs strukturÄjam savu kodu, nosaka tÄ mÄrogojamÄ«bu, uzturamÄ«bu un atkÄrtotu lietojamÄ«bu. IzstrÄdÄtÄjiem, kas strÄdÄ ar React, viens no fundamentÄlÄkajiem arhitektÅ«ras lÄmumiem ir saistÄ«ts ar to, kÄ koplietot loÄ£iku un lietotÄja saskarni (UI) starp komponentiem. Tas mÅ«s noved pie klasiskÄm debatÄm objektorientÄtajÄ programmÄÅ”anÄ, kas pÄrdomÄtas React komponentu balstÄ«tajai pasaulei: KompozÄ«cija pret MantoÅ”anu.
Ja jums ir pieredze ar klasiskÄm objektorientÄtÄm valodÄm, piemÄram, Java vai C++, mantoÅ”ana varÄtu Ŕķist dabiska pirmÄ izvÄle. Tas ir spÄcÄ«gs jÄdziens, lai izveidotu 'ir-a' (is-a) attiecÄ«bas. TomÄr oficiÄlÄ React dokumentÄcija sniedz skaidru un stingru ieteikumu: "Facebook mÄs izmantojam React tÅ«kstoÅ”iem komponentu, un mÄs neesam atraduÅ”i nevienu gadÄ«jumu, kurÄ mÄs ieteiktu veidot komponentu mantoÅ”anas hierarhijas."
Å is raksts sniegs visaptveroÅ”u Ŕīs arhitektÅ«ras izvÄles izpÄti. MÄs analizÄsim, ko mantoÅ”ana un kompozÄ«cija nozÄ«mÄ React kontekstÄ, parÄdÄ«sim, kÄpÄc kompozÄ«cija ir idiomatiskÄ un pÄrÄkÄ pieeja, un izpÄtÄ«sim spÄcÄ«gos modeļus ā no augstÄkÄs kÄrtas komponentiem lÄ«dz mÅ«sdienÄ«giem Hooks ā, kas padara kompozÄ«ciju par izstrÄdÄtÄja labÄko draugu, veidojot stabilas un elastÄ«gas lietojumprogrammas globÄlai auditorijai.
Izpratne par veco gvardi: Kas ir mantoŔana?
MantoÅ”ana ir viens no galvenajiem objektorientÄtÄs programmÄÅ”anas (OOP) pÄ«lÄriem. TÄ Ä¼auj jaunai klasei (apakÅ”klasei jeb bÄrnam) iegÅ«t esoÅ”Äs klases (superklases jeb vecÄka) Ä«paŔības un metodes. Tas rada cieÅ”i saistÄ«tas 'ir-a' attiecÄ«bas. PiemÄram, ZeltaRetrÄ«vers ir Suns, kas ir DzÄ«vnieks.
MantoÅ”ana Ärpus React konteksta
ApskatÄ«sim vienkÄrÅ”u JavaScript klaÅ”u piemÄru, lai nostiprinÄtu Å”o jÄdzienu:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Calls the parent constructor
this.breed = breed;
}
speak() { // Overrides the parent method
console.log(`${this.name} barks.`);
}
fetch() {
console.log(`${this.name} is fetching the ball!`);
}
}
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // Output: "Buddy barks."
myDog.fetch(); // Output: "Buddy is fetching the ball!"
Å ajÄ modelÄ« Dog klase automÄtiski saÅem name Ä«paŔību un speak metodi no Animal. TÄ var arÄ« pievienot savas metodes (fetch) un pÄrrakstÄ«t esoÅ”Äs. Tas rada stingru hierarhiju.
KÄpÄc mantoÅ”ana React vidÄ nedarbojas labi
Lai gan Å”is 'ir-a' modelis der dažÄm datu struktÅ«rÄm, tas rada bÅ«tiskas problÄmas, ja to piemÄro UI komponentiem React vidÄ:
- CieÅ”Ä sasaiste: Kad komponents manto no bÄzes komponenta, tas kļūst cieÅ”i saistÄ«ts ar tÄ vecÄka implementÄciju. IzmaiÅas bÄzes komponentÄ var negaidÄ«ti salauzt vairÄkus bÄrnu komponentus visÄ Ä·ÄdÄ. Tas padara refaktorÄÅ”anu un uzturÄÅ”anu par trauslu procesu.
- NeelastÄ«ga loÄ£ikas koplietoÅ”ana: Ko darÄ«t, ja vÄlaties koplietot noteiktu funkcionalitÄtes daļu, piemÄram, datu ielÄdi, ar komponentiem, kas neiederas tajÄ paÅ”Ä 'ir-a' hierarhijÄ? PiemÄram, gan
UserProfile, ganProductListvarÄtu bÅ«t nepiecieÅ”ams ielÄdÄt datus, bet nav jÄgas, lai tie mantotu no kopÄ«gaDataFetchingComponent. - "Prop-Drilling" elle: DziÄ¼Ä mantoÅ”anas Ä·ÄdÄ kļūst grÅ«ti nodot props no augstÄkÄ lÄ«meÅa komponenta uz dziļi ligzdotu bÄrnu. Jums var nÄkties nodot props caur starpkomponentiem, kas tos pat neizmanto, radot mulsinoÅ”u un uzpÅ«stu kodu.
- "Gorillas-banÄna problÄma": Slavens citÄts no OOP eksperta Džo Ärmstronga lieliski apraksta Å”o problÄmu: "Tu gribÄji banÄnu, bet dabÅ«ji gorillu, kas tur banÄnu, un visu džungļu." Ar mantoÅ”anu jÅ«s nevarat vienkÄrÅ”i iegÅ«t sev vÄlamo funkcionalitÄtes daļu; jÅ«s esat spiesti paÅemt lÄ«dzi visu superklasi.
Å o problÄmu dÄļ React komanda izstrÄdÄja bibliotÄku, balstoties uz elastÄ«gÄku un spÄcÄ«gÄku paradigmu: kompozÄ«ciju.
React pieejas pieÅemÅ”ana: KompozÄ«cijas spÄks
KompozÄ«cija ir dizaina princips, kas dod priekÅ”roku 'satur-a' (has-a) vai 'izmanto-a' (uses-a) attiecÄ«bÄm. TÄ vietÄ, lai komponents bÅ«tu cits komponents, tam pieder citi komponenti vai tas izmanto to funkcionalitÄti. Komponenti tiek uzskatÄ«ti par bÅ«vblokiem ā kÄ LEGO klucīŔi ā, kurus var dažÄdos veidos kombinÄt, lai izveidotu sarežģītus UI, neesot ieslÄgtiem stingrÄ hierarhijÄ.
React kompozÄ«cijas modelis ir neticami daudzpusÄ«gs, un tas izpaužas vairÄkos galvenajos modeļos. IzpÄtÄ«sim tos, sÄkot no visvienkÄrÅ”Äkajiem lÄ«dz vismodernÄkajiem un spÄcÄ«gÄkajiem.
1. tehnika: IetverŔana ar `props.children`
VistieÅ”ÄkÄ kompozÄ«cijas forma ir ietverÅ”ana. Tas ir gadÄ«jums, kad komponents darbojas kÄ vispÄrÄ«gs konteiners vai 'kaste', un tÄ saturs tiek nodots no vecÄkkomponenta. React Å”im nolÅ«kam ir Ä«paÅ”s, iebÅ«vÄts prop: props.children.
IedomÄjieties, ka jums ir nepiecieÅ”ams `Card` komponents, kas jebkuru saturu var ietÄ«t konsekventÄ rÄmÄ« ar Änu. TÄ vietÄ, lai ar mantoÅ”anu veidotu `TextCard`, `ImageCard` un `ProfileCard` variantus, jÅ«s izveidojat vienu vispÄrÄ«gu `Card` komponentu.
// Card.js - VispÄrÄ«gs konteinera komponents
function Card(props) {
return (
<div className="card">
{props.children}
</div>
);
}
// App.js - Card komponenta izmantoŔana
function App() {
return (
<div>
<Card>
<h1>Laipni lūdzam!</h1>
<p>Å is saturs atrodas Card komponentÄ.</p>
</Card>
<Card>
<img src="/path/to/image.jpg" alt="An example image" />
<p>Å Ä« ir attÄla kartÄ«te.</p>
</Card>
</div>
);
}
Å eit Card komponents nezina un tam nerÅ«p, ko tas satur. Tas vienkÄrÅ”i nodroÅ”ina ietveroÅ”o stilu. Saturs starp atveroÅ”o un aizveroÅ”o <Card> tagu automÄtiski tiek nodots kÄ props.children. Tas ir skaists atsaistes un atkÄrtotas lietojamÄ«bas piemÄrs.
2. tehnika: SpecializÄcija ar Props
Dažreiz komponentam ir nepiecieÅ”ami vairÄki 'caurumi', kurus aizpilda citi komponenti. Lai gan jÅ«s varÄtu izmantot `props.children`, skaidrÄks un strukturÄtÄks veids ir nodot komponentus kÄ parastus props. Å o modeli bieži sauc par specializÄciju.
Apsveriet `Modal` komponentu. ModÄlajam logam parasti ir virsraksta sadaļa, satura sadaļa un darbÄ«bu sadaļa (ar pogÄm, piemÄram, "ApstiprinÄt" vai "Atcelt"). MÄs varam izveidot savu `Modal` tÄ, lai tas pieÅemtu Ŕīs sadaļas kÄ props.
// Modal.js - SpecializÄtÄks konteiners
function Modal(props) {
return (
<div className="modal-backdrop">
<div className="modal-content">
<div className="modal-header">{props.title}</div>
<div className="modal-body">{props.body}</div>
<div className="modal-footer">{props.actions}</div>
</div>
</div>
);
}
// App.js - Modal izmantoÅ”ana ar konkrÄtiem komponentiem
function App() {
const confirmationTitle = <h2>ApstiprinÄt darbÄ«bu</h2>;
const confirmationBody = <p>Vai esat pÄrliecinÄts, ka vÄlaties turpinÄt Å”o darbÄ«bu?</p>;
const confirmationActions = (
<div>
<button>ApstiprinÄt</button>
<button>Atcelt</button>
</div>
);
return (
<Modal
title={confirmationTitle}
body={confirmationBody}
actions={confirmationActions}
/>
);
}
Å ajÄ piemÄrÄ Modal ir ļoti atkÄrtoti lietojams izkÄrtojuma komponents. MÄs to specializÄjam, nododot konkrÄtus JSX elementus tÄ `title`, `body` un `actions` props. Tas ir daudz elastÄ«gÄk nekÄ veidot `ConfirmationModal` un `WarningModal` apakÅ”klases. MÄs vienkÄrÅ”i sastÄdÄm `Modal` ar dažÄdu saturu pÄc vajadzÄ«bas.
3. tehnika: AugstÄkÄs kÄrtas komponenti (HOCs)
Lai koplietotu ne-UI loÄ£iku, piemÄram, datu ielÄdi, autentifikÄciju vai žurnalÄÅ”anu, React izstrÄdÄtÄji vÄsturiski izmantoja modeli, ko sauc par augstÄkÄs kÄrtas komponentiem (HOCs). Lai gan mÅ«sdienu React tos lielÄ mÄrÄ ir aizstÄjuÅ”i Hooks, ir svarÄ«gi tos saprast, jo tie pÄrstÄv galveno evolÅ«cijas soli React kompozÄ«cijas stÄstÄ un joprojÄm pastÄv daudzÄs kodu bÄzÄs.
HOC ir funkcija, kas pieÅem komponentu kÄ argumentu un atgriež jaunu, uzlabotu komponentu.
Izveidosim HOC ar nosaukumu `withLogger`, kas reÄ£istrÄ komponenta props katru reizi, kad tas tiek atjauninÄts. Tas ir noderÄ«gi atkļūdoÅ”anai.
// withLogger.js - HOC
import React, { useEffect } from 'react';
function withLogger(WrappedComponent) {
// Tas atgriež jaunu komponentu...
return function EnhancedComponent(props) {
useEffect(() => {
console.log('Component updated with new props:', props);
}, [props]);
// ... kas renderÄ oriÄ£inÄlo komponentu ar oriÄ£inÄlajiem props.
return <WrappedComponent {...props} />;
};
}
// MyComponent.js - Komponents, kuru uzlabot
function MyComponent({ name, age }) {
return (
<div>
<h1>Sveiki, {name}!</h1>
<p>Jums ir {age} gadi.</p>
</div>
);
}
// UzlabotÄ komponenta eksportÄÅ”ana
export default withLogger(MyComponent);
Funkcija `withLogger` ietin `MyComponent`, pieŔķirot tam jaunas žurnalÄÅ”anas iespÄjas, nemainot `MyComponent` iekÅ”Äjo kodu. MÄs varÄtu piemÄrot Å”o paÅ”u HOC jebkuram citam komponentam, lai pieŔķirtu tam to paÅ”u žurnalÄÅ”anas funkciju.
IzaicinÄjumi ar HOCs:
- IetīŔanas elle (Wrapper Hell): VairÄku HOC piemÄroÅ”ana vienam komponentam var radÄ«t dziļi ligzdotus komponentus React DevTools (piemÄram, `withAuth(withRouter(withLogger(MyComponent)))`), apgrÅ«tinot atkļūdoÅ”anu.
- Prop nosaukumu sadursmes: Ja HOC ievada prop (piemÄram, `data`), ko jau izmanto ietÄ«tais komponents, to var nejauÅ”i pÄrrakstÄ«t.
- NetieÅ”Ä loÄ£ika: No komponenta koda ne vienmÄr ir skaidrs, no kurienes nÄk tÄ props. LoÄ£ika ir paslÄpta HOC iekÅ”ienÄ.
4. tehnika: Render Props
Render Prop modelis parÄdÄ«jÄs kÄ risinÄjums dažiem HOC trÅ«kumiem. Tas piedÄvÄ skaidrÄku loÄ£ikas koplietoÅ”anas veidu.
Komponents ar render prop pieÅem funkciju kÄ prop (parasti nosauktu par `render`) un izsauc Å”o funkciju, lai noteiktu, ko renderÄt, nododot tai kÄ argumentus jebkÄdu stÄvokli vai loÄ£iku.
Izveidosim `MouseTracker` komponentu, kas seko peles X un Y koordinÄtÄm un padara tÄs pieejamas jebkuram komponentam, kas vÄlas tÄs izmantot.
// MouseTracker.js - Komponents ar render prop
import React, { useState, useEffect } from 'react';
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = (event) => {
setPosition({ x: event.clientX, y: event.clientY });
};
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
// Izsaucam render funkciju ar stÄvokli
return render(position);
}
// App.js - MouseTracker izmantoŔana
function App() {
return (
<div>
<h1>Kustiniet peli!</h1>
<MouseTracker
render={mousePosition => (
<p>PaÅ”reizÄjÄ peles pozÄ«cija ir ({mousePosition.x}, {mousePosition.y})</p>
)}
/>
</div>
);
}
Å eit `MouseTracker` ietver visu loÄ£iku peles kustÄ«bas izsekoÅ”anai. Tas pats par sevi neko nerenderÄ. TÄ vietÄ tas deleÄ£Ä renderÄÅ”anas loÄ£iku savam `render` prop. Tas ir skaidrÄk nekÄ HOC, jo jÅ«s varat redzÄt tieÅ”i no kurienes nÄk `mousePosition` dati tieÅ”i JSX iekÅ”ienÄ.
`children` prop var izmantot arÄ« kÄ funkciju, kas ir izplatÄ«ta un eleganta Ŕī modeļa variÄcija:
// Izmantojot children kÄ funkciju
<MouseTracker>
{mousePosition => (
<p>PaÅ”reizÄjÄ peles pozÄ«cija ir ({mousePosition.x}, {mousePosition.y})</p>
)}
</MouseTracker>
5. tehnika: Hooks (MÅ«sdienÄ«gÄ un ieteicamÄ pieeja)
Ieviests React 16.8, Hooks radikÄli mainÄ«ja veidu, kÄ mÄs rakstÄm React komponentus. Tie ļauj izmantot stÄvokli un citas React funkcijas funkcionÄlajos komponentos. VissvarÄ«gÄkais ir tas, ka pielÄgotie Hooks nodroÅ”ina elegantÄko un tieÅ”Äko risinÄjumu stÄvokļa loÄ£ikas koplietoÅ”anai starp komponentiem.
Hooks atrisina HOC un Render Props problÄmas daudz tÄ«rÄkÄ veidÄ. PÄrveidosim mÅ«su `MouseTracker` piemÄru par pielÄgotu hook, ko sauc par `useMousePosition`.
// hooks/useMousePosition.js - PielÄgots Hook
import { useState, useEffect } from 'react';
export function useMousePosition() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (event) => {
setPosition({ x: event.clientX, y: event.clientY });
};
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []); // TukÅ”s atkarÄ«bu masÄ«vs nozÄ«mÄ, ka Å”is efekts tiek izpildÄ«ts tikai vienu reizi
return position;
}
// DisplayMousePosition.js - Komponents, kas izmanto Hook
import { useMousePosition } from './hooks/useMousePosition';
function DisplayMousePosition() {
const position = useMousePosition(); // VienkÄrÅ”i izsauciet hook!
return (
<p>
Peles pozīcija ir ({position.x}, {position.y})
</p>
);
}
// Cits komponents, varbūt interaktīvs elements
import { useMousePosition } from './hooks/useMousePosition';
function InteractiveBox() {
const { x, y } = useMousePosition();
const style = {
position: 'absolute',
top: y - 25, // CentrÄ kasti uz kursora
left: x - 25,
width: '50px',
height: '50px',
backgroundColor: 'lightblue',
};
return <div style={style} />;
}
Tas ir milzÄ«gs uzlabojums. Nav 'ietīŔanas elles', nav prop nosaukumu sadursmju un nav sarežģītu render prop funkciju. LoÄ£ika ir pilnÄ«bÄ atsaistÄ«ta atkÄrtoti lietojamÄ funkcijÄ (`useMousePosition`), un jebkurÅ” komponents var 'pieÄ·erties' Å”ai stÄvokļa loÄ£ikai ar vienu, skaidru koda rindiÅu. PielÄgotie Hooks ir kompozÄ«cijas galvenÄ izpausme mÅ«sdienu React, ļaujot jums izveidot savu atkÄrtoti lietojamu loÄ£ikas bloku bibliotÄku.
Ätrs salÄ«dzinÄjums: KompozÄ«cija pret MantoÅ”anu React vidÄ
Lai apkopotu galvenÄs atŔķirÄ«bas React kontekstÄ, Å”eit ir tieÅ”s salÄ«dzinÄjums:
| Aspekts | MantoÅ”ana (Anti-modelis React vidÄ) | KompozÄ«cija (IeteicamÄ pieeja React vidÄ) |
|---|---|---|
| AttiecÄ«bas | 'ir-a' (is-a) attiecÄ«bas. SpecializÄts komponents ir bÄzes komponenta versija. | 'satur-a' (has-a) vai 'izmanto-a' (uses-a) attiecÄ«bas. Sarežģītam komponentam pieder mazÄki komponenti vai tas izmanto kopÄ«gu loÄ£iku. |
| Sasaiste | Augsta. BÄrnu komponenti ir cieÅ”i saistÄ«ti ar to vecÄka implementÄciju. | Zema. Komponenti ir neatkarÄ«gi un tos var atkÄrtoti izmantot dažÄdos kontekstos bez modifikÄcijÄm. |
| ElastÄ«ba | Zema. Stingras, uz klasÄm balstÄ«tas hierarhijas apgrÅ«tina loÄ£ikas koplietoÅ”anu starp dažÄdiem komponentu kokiem. | Augsta. LoÄ£iku un UI var kombinÄt un atkÄrtoti izmantot neskaitÄmos veidos, kÄ bÅ«vblokus. |
| Koda atkÄrtota lietojamÄ«ba | Ierobežota ar iepriekÅ” definÄtu hierarhiju. JÅ«s saÅemat visu "gorillu", kad vÄlaties tikai "banÄnu". | Lieliska. Mazus, fokusÄtus komponentus un hooks var izmantot visÄ lietojumprogrammÄ. |
| React idioma | OficiÄlÄ React komanda to neiesaka. | IeteicamÄ un idiomatiskÄ pieeja React lietojumprogrammu veidoÅ”anai. |
NoslÄgums: DomÄjiet kompozÄ«cijÄ
Debates par kompozÄ«ciju un mantoÅ”anu ir fundamentÄls temats programmatÅ«ras dizainÄ. Lai gan mantoÅ”anai ir sava vieta klasiskajÄ OOP, UI izstrÄdes dinamiskÄ, uz komponentiem balstÄ«tÄ daba padara to par sliktu izvÄli React videi. BibliotÄka tika fundamentÄli izstrÄdÄta, lai pieÅemtu kompozÄ«ciju.
Dodot priekŔroku kompozīcijai, jūs iegūstat:
- ElastÄ«bu: SpÄju pÄc vajadzÄ«bas jaukt un saskaÅot UI un loÄ£iku.
- UzturamÄ«bu: VÄji saistÄ«tus komponentus ir vieglÄk saprast, testÄt un refaktorÄt izolÄti.
- MÄrogojamÄ«bu: KompozicionÄla domÄÅ”ana veicina mazu, atkÄrtoti lietojamu komponentu un hooks dizaina sistÄmas izveidi, ko var efektÄ«vi izmantot lielu, sarežģītu lietojumprogrammu veidoÅ”anai.
KÄ globÄlam React izstrÄdÄtÄjam kompozÄ«cijas apgūŔana nav tikai labÄko prakÅ”u ievÄroÅ”ana ā tÄ ir izpratne par galveno filozofiju, kas padara React par tik spÄcÄ«gu un produktÄ«vu rÄ«ku. SÄciet, veidojot mazus, fokusÄtus komponentus. Izmantojiet `props.children` vispÄrÄ«giem konteineriem un props specializÄcijai. LoÄ£ikas koplietoÅ”anai vispirms izmantojiet pielÄgotos Hooks. DomÄjot kompozÄ«cijÄ, jÅ«s bÅ«siet ceÄ¼Ä uz elegantu, stabilu un mÄrogojamu React lietojumprogrammu veidoÅ”anu, kas izturÄs laika pÄrbaudi.